#include "message.h"
#include "game.h"
#include "item.h"
#include "creature.h"

MessageBank::MessageBank( Game& game )
: _game( game )
{
}

enum Visibility
{
    HIDDEN,
    ACTOR_VISIBLE,
    ACTOR_PLAYER,
    ITEM_PLAYER,
    ITEM_VISIBLE
};

#define FOR( mt, a ) { if ( m == mt ) { a } }
#define REPLACE( s, t ) { std::size_t i = ss.find( s ); while ( i != std::string::npos ) { ss.replace( i, std::string( s ).length(), t ); i = ss.find( s ); } }
#define CHECK_VIS( thing ) uint thing##Vis = HIDDEN; Creature* thing##Car = 0; { Actor* a; Creature* c; bool ignore; if ( thing->IsPlayer() ) thing##Vis = ACTOR_PLAYER; else if ( thing->Call< BIIsActor >( &a ) && a ) { if ( a->CanBeSeenByPlayer() ) thing##Vis = ACTOR_VISIBLE; } else if ( thing->Call< BIItemCarrier >( &c, &ignore, &ignore ) && c ) { thing##Car = c; Item* it; thing->Call< BIIsItem >( &it ); if ( c->IsPlayer() ) thing##Vis = ITEM_PLAYER; else if ( c->CanBeSeenByPlayer() && it /*&& ( it->IsWorn() || it->IsWielded() )*/ ) thing##Vis = ITEM_VISIBLE; } }
#define CHECK_NAME( thing ) std::string thing##Name, thing##Indef; bool thing##Plural; std::string thing##CarName, thing##CarIndef; bool thing##CarPlural; { bool ignore; thing->Call< BIName >( &thing##Name, &thing##Plural, ARTICLE_NONE ); thing->Call< BIName >( &thing##Indef, &ignore, ARTICLE_INDEFINITE ); { Creature* c; bool ignore; if ( thing->Call< BIItemCarrier >( &c, &ignore, &ignore ) && c ) { c->Call< BIName >( &thing##CarName, &thing##CarPlural, ARTICLE_NONE ); c->Call< BIName >( &thing##CarIndef, &thing##CarPlural, ARTICLE_INDEFINITE ); } } }
#define CHECK_REPLACE( name, indef, prefix ) REPLACE( name, prefix##Name ); REPLACE( indef, prefix##Indef )
#define HIDDEN( prefix ) ( prefix##Vis == HIDDEN )
#define VISIBLE( prefix ) ( prefix##Vis == ACTOR_VISIBLE )
#define PLAYER( prefix ) ( prefix##Vis == ACTOR_PLAYER )
#define ITEM( prefix ) ( prefix##Vis == ITEM_VISIBLE )
#define PITEM( prefix ) ( prefix##Vis == ITEM_PLAYER )
#define EQUAL( p, q ) ( ( p ) == ( q ) )
#define RET( s ) ss = ( s ); goto end;
#define TRY( c, s ) { if ( c ) { RET( s ); } }
#define A( p, s ) TRY( true, s )
#define H( p, s ) TRY( HIDDEN( p ),  s )
#define V( p, s ) TRY( VISIBLE( p ), s )
#define P( p, s ) TRY( PLAYER( p ),  s )
#define C( p, s ) TRY( ITEM( p ),    s )
#define I( p, s ) TRY( PITEM( p ),   s )
#define A_A( p, q, s ) TRY( true, s )
#define H_A( p, q, s ) H( p, s )
#define V_A( p, q, s ) V( p, s )
#define P_A( p, q, s ) P( p, s )
#define C_A( p, q, s ) C( p, s )
#define I_A( p, q, s ) I( p, s )
#define A_H( p, q, s ) H( q, s )
#define A_V( p, q, s ) V( q, s )
#define A_P( p, q, s ) P( q, s )
#define A_C( p, q, s ) C( q, s )
#define A_I( p, q, s ) I( q, s )
#define H_H( p, q, s ) TRY( HIDDEN( p )  && HIDDEN( q ),  s )
#define H_V( p, q, s ) TRY( HIDDEN( p )  && VISIBLE( q ), s )
#define H_P( p, q, s ) TRY( HIDDEN( p )  && PLAYER( q ),  s )
#define H_C( p, q, s ) TRY( HIDDEN( p )  && ITEM( q ),    s )
#define H_I( p, q, s ) TRY( HIDDEN( p )  && PITEM( q ),   s )
#define V_H( p, q, s ) TRY( VISIBLE( p ) && HIDDEN( q ),  s )
#define V_V( p, q, s ) TRY( VISIBLE( p ) && VISIBLE( q ), s )
#define V_P( p, q, s ) TRY( VISIBLE( p ) && PLAYER( q ),  s )
#define V_C( p, q, s ) TRY( VISIBLE( p ) && ITEM( q ),    s )
#define V_I( p, q, s ) TRY( VISIBLE( p ) && PITEM( q ),   s )
#define P_H( p, q, s ) TRY( PLAYER( p )  && HIDDEN( q ),  s )
#define P_V( p, q, s ) TRY( PLAYER( p )  && VISIBLE( q ), s )
#define P_P( p, q, s ) TRY( PLAYER( p )  && PLAYER( q ),  s )
#define P_C( p, q, s ) TRY( PLAYER( p )  && ITEM( q ),    s )
#define P_I( p, q, s ) TRY( PLAYER( p )  && PITEM( q ),   s )
#define C_H( p, q, s ) TRY( ITEM( p )    && HIDDEN( q ),  s )
#define C_V( p, q, s ) TRY( ITEM( p )    && VISIBLE( q ), s )
#define C_P( p, q, s ) TRY( ITEM( p )    && PLAYER( q ),  s )
#define C_C( p, q, s ) TRY( ITEM( p )    && ITEM( q ),    s )
#define C_I( p, q, s ) TRY( ITEM( p )    && PITEM( q ),   s )
#define I_H( p, q, s ) TRY( PITEM( p )   && HIDDEN( q ),  s )
#define I_V( p, q, s ) TRY( PITEM( p )   && VISIBLE( q ), s )
#define I_P( p, q, s ) TRY( PITEM( p )   && PLAYER( q ),  s )
#define I_C( p, q, s ) TRY( PITEM( p )   && ITEM( q ),    s )
#define I_I( p, q, s ) TRY( PITEM( p )   && PITEM( q ),   s )
#define VEV( p, q, s ) TRY( VISIBLE( p ) && VISIBLE( q ) && EQUAL( p, q ), s )
#define VEC( p, q, s ) TRY( VISIBLE( p ) && ITEM( q )    && EQUAL( p, q ), s )
#define CEC( p, q, s ) TRY( ITEM( p )    && ITEM( q )    && EQUAL( p, q ), s )
#define IEI( p, q, s ) TRY( PITEM( p )   && PITEM( q )   && EQUAL( p, q ), s )

std::string MessageBank::GetPlayerUI( uint m, Actor* plr )
{
    CHECK_VIS( plr );
    std::string ss;

    FOR( PLAYERUI_QUERY_PUSH, P( plr, "What do you want to push?" ) );
    FOR( PLAYERUI_QUERY_PULL, P( plr, "Which direction do you want to pull in?" ) );
    FOR( PLAYERUI_QUERY_LOOK, P( plr, "What do you want to look at?" ) );
    FOR( PLAYERUI_QUERY_LIGHT, P( plr, "What do you want to set alight?" ) );
    FOR( PLAYERUI_QUERY_PICKUP, P( plr, "What do you want to pick up?" ) );
    FOR( PLAYERUI_QUERY_DROP, P( plr, "What do you want to drop?" ) );
    FOR( PLAYERUI_QUERY_WEAR, P( plr, "What do you want to wear?" ) );
    FOR( PLAYERUI_QUERY_WIELD, P( plr, "What do you want to wield?" ) );
    FOR( PLAYERUI_QUERY_REMOVE, P( plr, "What do you want to remove?" ) );
    FOR( PLAYERUI_QUERY_EAT, P( plr, "What do you want to eat or drink?" ) );
    FOR( PLAYERUI_LOOK_DARK, P( plr, "You can't see that." ) );
    FOR( PLAYERUI_PICKUP_DARK, P( plr, "You fumble around in the dark." ) );
    FOR( PLAYERUI_BLOCKED_DARK, P( plr, "You are blocked by something in the dark." ) );
    FOR( PLAYERUI_NOTHING_HERE, P( plr, "There isn't anything here." ) );
    FOR( PLAYERUI_NOTHING_INVENTORY, P( plr, "You don't have anything in your inventory." ) );
    FOR( PLAYERUI_NOTHING_FIRESOURCE, P( plr, "You don't have any source of fire." ) );
    FOR( PLAYERUI_PICKUP_FAIL, P( plr, "You don't have the strength to lift any more." ) );
    FOR( PLAYERUI_PUSH_FAIL, P( plr, "It doesn't budge." ) );
    FOR( PLAYERUI_PUSH_NOTHING, P( plr, "You push into empty air." ) );
    FOR( PLAYERUI_PULL_NOTHING, P( plr, "You grab at empty air." ) );
    FOR( PLAYERUI_PULL_BLOCKED, P( plr, "Your back is blocked." ) );
    FOR( PLAYERUI_FAIL_WEARING, P( plr, "You are wearing that." ) );
    FOR( PLAYERUI_FAIL_WIELDING, P( plr, "You are wielding that." ) );
    FOR( PLAYERUI_FAIL_UNWEARABLE, P( plr, "You can't wear that." ) );
    FOR( PLAYERUI_FAIL_UNWIELDABLE, P( plr, "You can't wield that." ) );
    FOR( PLAYERUI_FAIL_ALREADY_WORN, P( plr, "You are already wearing that." ) );
    FOR( PLAYERUI_FAIL_ALREADY_WIELDED, P( plr, "You are already wielding that." ) );
    FOR( PLAYERUI_FAIL_NEED_FREE_HAND, P( plr, "You need a free hand to wield that." ) );
    FOR( PLAYERUI_FAIL_NEED_BOTH_HANDS, P( plr, "You need both hands free to wield that." ) );
    FOR( PLAYERUI_FAIL_RING, P( plr, "You can't wear any more rings." ) );
    FOR( PLAYERUI_FAIL_NECK, P( plr, "You are already wearing something around your neck." ) );
    FOR( PLAYERUI_FAIL_HAND, P( plr, "You are already wearing something on your hands." ) );
    FOR( PLAYERUI_FAIL_FEET, P( plr, "You are already wearing something on your feet." ) );
    FOR( PLAYERUI_FAIL_HEAD, P( plr, "You are already wearing something on your head." ) );
    FOR( PLAYERUI_FAIL_BODY, P( plr, "You are already wearing something on your body." ) );
    FOR( PLAYERUI_FAIL_BODY, P( plr, "You are already wearing something on your body." ) );
    FOR( PLAYERUI_FAIL_NOT_EQUIPPED, P( plr, "You aren't wearing or wielding that." ) );
end:
    return ss;
}

std::string MessageBank::GetUnary( uint m, Behaved* trg )
{
    CHECK_VIS( trg );
    CHECK_NAME( trg );
    std::string ss = "";

    FOR( UNARY_FIRE_DESTROY_INSTANT,
        P( trg, "You go up in smoke." )
        I( trg, trgPlural ? "Your %TRG go up in smoke." : "Your %TRG goes up in smoke." )
        C( trg, trgPlural ? "The %CAR's %TRG go up in smoke." : "The %CAR's %TRG goes up in smoke." )
        V( trg, trgPlural ? "The %TRG go up in smoke." : "The %TRG goes up in smoke." )
    );
    FOR( UNARY_FIRE_DESTROY_EVENTUAL,
        P( trg, "You turn to ash." )
        I( trg, trgPlural ? "Your %TRG turn to ash." : "Your %TRG turns to ash." )
        C( trg, trgPlural ? "The %CAR's %TRG turn to ash." : "The %CAR's %TRG turns to ash." )
        V( trg, trgPlural ? "The %TRG turn to ash." : "The %TRG turns to ash." )
    );
    FOR( UNARY_FIRE_CATCH_FIRE_BRIGHT,
        P( trg, "You burst into flames." )
        I( trg, trgPlural ? "Your %TRG burst into flames." : "Your %TRG bursts into flames." )
        C( trg, trgPlural ? "The %CAR's %TRG burst into flames." : "The %CAR's %TRG bursts into flames." )
        V( trg, trgPlural ? "The %TRG burst into flames." : "The %TRG bursts into flames." )
    );
    FOR( UNARY_FIRE_CATCH_FIRE,
        P( trg, "You catch fire." )
        I( trg, trgPlural ? "Your %TRG catch fire." : "Your %TRG catches fire." )
        C( trg, trgPlural ? "The %CAR's %TRG catch fire." : "The %CAR's %TRG catches fire." )
        V( trg, trgPlural ? "The %TRG catch fire." : "The %TRG catches fire." )
    );
    FOR( UNARY_FIRE_SMOULDER,
        P( trg, "You smoulder." )
        I( trg, trgPlural ? "Your %TRG smoulder." : "Your %TRG smoulders." )
        C( trg, trgPlural ? "The %CAR's %TRG smoulder." : "The %CAR's %TRG smoulders." )
        V( trg, trgPlural ? "The %TRG smoulder." : "The %TRG smoulders." )
    );
    FOR( UNARY_FIRE_CHAR,
        P( trg, "You char." )
        I( trg, trgPlural ? "Your %TRG char." : "Your %TRG chars." )
        C( trg, trgPlural ? "The %CAR's %TRG char." : "The %CAR's %TRG chars." )
        V( trg, trgPlural ? "The %TRG char." : "The %TRG chars." )
    );
    FOR( UNARY_FIRE_GO_OUT,
        P( trg, "You go out." )
        I( trg, trgPlural ? "Your %TRG go out." : "Your %TRG goes out." )
        C( trg, trgPlural ? "The %CAR's %TRG go out." : "The %CAR's %TRG goes out." )
        V( trg, trgPlural ? "The %TRG go out." : "The %TRG goes out." )
    );

end:
    CHECK_REPLACE( "%TRG", "%ITRG", trg );
    CHECK_REPLACE( "%CAR", "%ICAR", trgCar );
    return ss;
}

std::string MessageBank::GetBinary( uint m, Actor* src, Actor* trg )
{
    CHECK_VIS( src );
    CHECK_VIS( trg );
    CHECK_NAME( src );
    CHECK_NAME( trg );
    std::string ss = "";

    FOR( BINARY_SHOVE_FAIL,
        P_V( src, trg, "You are blocked by the %TRG." )
        P_H( src, trg, "You are blocked by something." )
        V_P( src, trg, "The %SRC pushes against you." )
        H_P( src, trg, "Something pushes against you." )
    );
    FOR( BINARY_DRAG_FAIL,
        P_V( src, trg, "The %TRG doesn't move." )
        P_H( src, trg, "You grab at something." )
        V_P( src, trg, "The %SRC grabs at you." )
        H_P( src, trg, "Something grabs at you." )
    );
    FOR( BINARY_DRAG_SUCCEED,
        P_V( src, trg, "You drag the %TRG." )
        P_H( src, trg, "You drag something." )
        V_P( src, trg, "The %SRC drags you." )
        H_P( src, trg, "Something drags you." )
    );
    FOR( BINARY_PUSH_SUCCEED,
        P_V( src, trg, "You push past the %TRG." )
        P_H( src, trg, "You push past something." )
        V_P( src, trg, "The %SRC pushes past you." )
        H_P( src, trg, "Something pushes past you." )
    );
    FOR( BINARY_SHOVE_SUCCEED,
        P_V( src, trg, "You shove the %TRG." )
        P_H( src, trg, "You shove something." )
        V_P( src, trg, "The %SRC shoves you." )
        H_P( src, trg, "Something shoves you." )
    );
    FOR( BINARY_SHOVE_SUCCEED,
        P_V( src, trg, "You shove the %TRG." )
        P_H( src, trg, "You shove something." )
        V_P( src, trg, "The %SRC shoves you." )
        H_P( src, trg, "Something shoves you." )
    );
    FOR( BINARY_ITEM_DROP,
        P_A( src, trg, "You drop the %TRG." )
        V_V( src, trg, "The %SRC drops %ITRG." )
        V_H( src, trg, "The %SRC drops something." )
        V_P( src, trg, "The %SRC drops you." )
    );

end:
    CHECK_REPLACE( "%TRG", "%ITRG", trg );
    CHECK_REPLACE( "%SRC", "%ISRC", src );
    return ss;
}

std::string MessageBank::GetManipulation( uint m, Actor* src, Item* trg )
{
    CHECK_VIS( src );
    CHECK_NAME( src );
    CHECK_NAME( trg );
    std::string ss = "";

    FOR( MANIPULATION_WEAR, 
        V( src, "The %SRC wears %ITRG." )
        P( src, "You wear the %TRG." )
    );
    FOR( MANIPULATION_WIELD_MAIN,
        V( src, "The %SRC wields %ITRG." )
        P( src, "You wield the %TRG in your main hand." )
    );
    FOR( MANIPULATION_WIELD_FREE,
        V( src, "The %SRC wields %ITRG." )
        P( src, "You wield the %TRG in your free hand." )
    );
    FOR( MANIPULATION_WIELD_BOTH,
        V( src, "The %SRC wields %ITRG." )
        P( src, "You wield the %TRG in both hands." )
    );
    FOR( MANIPULATION_UNWEAR,
        V( src, "The %SRC takes off %ITRG." )
        P( src, "You take off the %TRG." )
    );
    FOR( MANIPULATION_UNWIELD,
        V( src, "The %SRC puts away %ITRG." )
        P( src, "You put away the %TRG." )
    );
    FOR( MANIPULATION_EAT_RING,
        P( src, "You swallow the %TRG." )
        V( src, "The %SRC swallows %ITRG." )
    );
    FOR( MANIPULATION_EAT_LEATHER,
        P( src, trgPlural ? "You eat the %TRG. They are tough and chewy." : "You eat the %TRG. It is tough and chewy." )
        V( src, "The %SRC eats %ITRG." )
    );
    FOR( MANIPULATION_EAT_CHARRED_LEATHER,
        P( src, trgPlural ? "You eat the %TRG. They are almost palatable." : "You eat the %TRG. It is almost palatable." )
        V( src, "The %SRC eats %ITRG." )
    );
    FOR( MANIPULATION_EAT_TORCH,
        P( src, "You eat the %TRG. It tastes strongly of sulphur." )
        V( src, "The %SRC eats %ITRG." )
    );
    FOR( MANIPULATION_EAT_MATCHES,
        P( src, trgPlural ? "You eat the %TRG. They taste strongly of phosphorus." : "You eat the %TRG. It tastes strongly of phosphorus." )
        V( src, "The %SRC eats %ITRG." )
    );
    FOR( MANIPULATION_EAT_OTHER,
        P( src, "You eat the %TRG." )
        V( src, "The %SRC eats %ITRG." )
    );
    FOR( MANIPULATION_DRINK_OTHER,
        P( src, "You drink the %TRG." )
        V( src, "The %SRC drinks %ITRG." )
    );

end:
    CHECK_REPLACE( "%TRG", "%ITRG", trg );
    CHECK_REPLACE( "%SRC", "%ISRC", src );
    return ss;
}

std::string MessageBank::GetTernary( uint m, Actor* src, Actor* trg, Behaved* wth )
{
    CHECK_VIS( src );
    CHECK_VIS( trg );
    CHECK_VIS( wth );
    CHECK_NAME( src );
    CHECK_NAME( trg );
    CHECK_NAME( wth );
    std::string ss = "";

    FOR( TERNARY_ALIGHT_FROM_BRAZIER,
        P_P( trg, wth, src->IsPlayer() ? "You burn." : "" )
        VEV( trg, wth, src->IsPlayer() ? "The &TRG burns." : "" )
        H_P( src, trg, wthVis ? "Something holds you in the brazier." : "Something holds you to something burning." )
        VEV( src, trg, wthVis ? "The %SRC holds itself in the brazier." : "The %SRC holds itself to something burning." )
        V_P( src, trg, wthVis ? "The %SRC holds you in the brazier." : "The %SRC holds you to something burning." )
        P_P( src, trg, wthVis ? "You hold your body in the brazier." : "You hold your body to something burning." )
        H_P( src, wth, trgVis ? "Something thrusts the %TRG at you." : "Something is thrust at you." )
        VEV( src, wth, trgVis ? "The %SRC holds the %TRG in itself." : "The %SRC holds something in itself." )
        V_V( src, wth, trgVis ? "The %SRC holds the %TRG in the brazier." : "The %SRC holds something in the brazier." )
        V_P( src, wth, trgVis ? "The %SRC holds the %TRG to you." : "The %SRC holds %ITRG to you." )
        P_H( src, wth, trgVis ? "You wave the %TRG around." : "You wave something around." )
        P_V( src, wth, trgVis ? "You hold the %TRG in the brazier." : "You hold something in the brazier." )
        P_P( src, wth, trgVis ? "You hold the %TRG to yourself." : "You hold something to yourself." )
    );
    FOR( TERNARY_ALIGHT_FROM_BURNING_OBJECT,
        P_P( trg, wth, src->IsPlayer() ? "Your body burns." : "" )
        VEV( trg, wth, src->IsPlayer() ? "The &TRG burns." : "" )
        P_C( trg, wth, srcVis ? "The %SRC you to %IWTH." : "Something holds you to something burning." )
        H_P( src, trg, wthVis ? "Something holds you to the %WTH." : "Something holds you to something burning." )
        VEV( src, trg, wthVis ? "The %SRC holds %IWTH to itself." : "The %SRC holds something to itself." )
        V_P( src, trg, wthVis ? "The %SRC holds you to the %WTH." : "The %SRC holds you to something burning." )
        P_P( src, trg, wthVis ? "You hold your body to the %WTH." : "You hold your body to something burning." )
        H_P( src, wth, trgVis ? "Something thrusts the %TRG at your burning body." : "Something is thrust at your burning body." )
        VEV( src, wth, trgVis ? "The %SRC holds the %TRG to its burning body." : "The %SRC holds something to its burning body." )
        V_V( src, wth, trgVis ? "The %SRC holds the %TRG to the %WTH." : "The %SRC holds something to the %WTH." )
        V_P( src, wth, trgVis ? "The %SRC holds the %TRG to your burning body." : "The %SRC holds something to your burning body." )
        V_C( src, wth, trgVis ? "The %SRC holds the %TRG to %IWTH." : "The %SRC holds something to %IWTH." )
        P_H( src, wth, trgVis ? "You wave the %TRG around." : "You wave something around." )
        P_V( src, wth, trgVis ? "You hold the %TRG to the %WTH." : "You hold something to the %WTH." )
        P_P( src, wth, trgVis ? "You hold the %TRG to your burning body." : "You hold something to your burning body." )
        P_I( src, wth, trgVis ? "You hold the %TRG to your %WTH." : "You hold something to your %WTH." )
    );
    FOR( TERNARY_ALIGHT_FROM_MATCH,
        IEI( trg, wth, "Your %TRG burns." );
        H_P( src, trg, "Something lights a match and holds it to your body." )
        VEV( src, trg, "The %SRC lights a match and holds it to itself." )
        V_P( src, trg, "The %SRC lights a match and holds it to your body." )
        P_P( src, trg, "You light a match and hold it to your body." )
        V_C( src, wth, trgVis ? "The %SRC lights a match and holds it to the %TRG." : "The %SRC lights a match and holds it to something." )
        P_I( src, wth, trgVis ? "You light a match and hold it to the %TRG." : "You light a match and hold it something." )
    );

end:
    CHECK_REPLACE( "%TRG", "%ITRG", trg );
    CHECK_REPLACE( "%SRC", "%ISRC", src );
    CHECK_REPLACE( "%WTH", "%IWTH", wth );
    return ss;
}

std::string MessageBank::GetManipulationWith( uint m, Actor* src, Item* trg, Behaved* wth )
{
    CHECK_VIS( src );
    CHECK_VIS( trg );
    CHECK_VIS( wth );
    CHECK_NAME( src );
    CHECK_NAME( trg );
    CHECK_NAME( wth );
    std::string ss = "";

    FOR( MANIPULATIONWITH_ALIGHT_FROM_BRAZIER,
        H_P( src, wth, "Something is thrust at you." )
        VEV( src, wth, "The $SRC holds %ITRG to itself." )
        V_V( src, wth, "The %SRC holds %ITRG in the brazier." )
        V_P( src, wth, "The %SRC holds %ITRG to you." )
        P_H( src, wth, "You wave your %TRG around." )
        P_V( src, wth, "You hold your %TRG in the brazier." )
        P_P( src, wth, "You hold your %TRG to yourself." )
    );
    FOR( MANIPULATIONWITH_ALIGHT_FROM_BURNING_OBJECT,
        IEI( trg, wth, "Your %TRG burns." );
        H_P( src, wth, "Something is thrust at your burning body." )
        VEV( src, wth, "The $SRC holds %ITRG to its burning body." )
        V_V( src, wth, "The %SRC holds %ITRG to the %WTH." )
        V_P( src, wth, "The %SRC holds %ITRG to your burning body." )
        V_C( src, wth, "The %SRC holds %ITRG to %IWTH." )
        P_H( src, wth, "You wave your %TRG around." )
        P_V( src, wth, "You hold your %TRG to the %WTH." )
        P_P( src, wth, "You hold your %TRG to your burning body." )
        P_I( src, wth, "You hold your %TRG to your %WTH." )
    );
    FOR( MANIPULATIONWITH_ALIGHT_FROM_MATCH,
        IEI( trg, wth, "Your %TRG burns." );
        V_C( src, wth, "The %SRC lights a match and holds it to %ITRG." )
        P_I( src, wth, "You light a match and hold it to your %TRG." )
    );
end:
    CHECK_REPLACE( "%TRG", "%ITRG", trg );
    CHECK_REPLACE( "%SRC", "%ISRC", src );
    CHECK_REPLACE( "%WTH", "%IWTH", wth );
    return ss;
}

std::string MessageBank::GetTernarySwitch( uint m, Actor* source, Behaved* target, Behaved* with )
{
    Actor* actor;
    Item* item;
    if ( target->Call< BIIsActor >( &actor ) && actor )
        return GetTernary( m, source, actor, with );
    else if ( target->Call< BIIsItem >( &item ) && item )
        return GetManipulationWith( m, source, item, with );
    return "";
}

void MessageBank::PlayerUI( uint m, Actor* player )
{
    std::string s = GetPlayerUI( m, player );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::Unary( uint m, Behaved* target )
{
    std::string s = GetUnary( m, target );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::Binary( uint m, Actor* source, Actor* target )
{
    std::string s = GetBinary( m, source, target );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::Manipulation( uint m, Actor* source, Item* target )
{
    std::string s = GetManipulation( m, source, target );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::Ternary( uint m, Actor* source, Actor* target, Behaved* with )
{
    std::string s = GetTernary( m, source, target, with );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::ManipulationWith( uint m, Actor* source, Item* target, Behaved* with )
{
    std::string s = GetManipulationWith( m, source, target, with );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::TernarySwitch( uint m, Actor* source, Behaved* target, Behaved* with )
{
    std::string s = GetTernarySwitch( m, source, target, with );
    if ( !s.empty() )
        Queue( s );
}

void MessageBank::Queue( const ustring& s )
{
    _game.QueueMessage( s );
}

void MessageBank::Queue( const std::string& s )
{
    _game.QueueMessage( s );
}